<?php
/**
 * 创建人 : Forpastime
 * 创建时间: 2023/4/18 14:57
 * 个人主页 : http://forpastime.com
 */

namespace App\Utils;

use App\Annotation\AdminNode;
use Hyperf\Di\Annotation\AnnotationCollector;
use Hyperf\Di\Exception\ConflictAnnotationException;
use Hyperf\Di\ReflectionManager;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\HttpServer\Annotation\Controller;
use ReflectionMethod;
use Hyperf\Utils\Str;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Annotation\Mapping;
use Hyperf\HttpServer\Annotation\PatchMapping;
use Hyperf\HttpServer\Annotation\PostMapping;
use Hyperf\HttpServer\Annotation\PutMapping;
use Hyperf\HttpServer\Annotation\RequestMapping;

class RoutesToNodes
{
    public static function handleAutoController(string $className, AutoController $annotation, array $methodMetadata = [], AdminNode $adminNodeData = null)
    {
        $class = ReflectionManager::reflectClass($className);
        $methods = $class->getMethods(ReflectionMethod::IS_PUBLIC);
        $prefix = self::getPrefix($className, $annotation->prefix);
        $rootNode = $adminNode = [];
        if(!empty($adminNodeData)){
            $rootNode = $adminNodeData->toArray();
            //类节点注解不为空
            $rootNode['parent_id']=0;
            $rootNode['control_name']=$prefix;
            $rootNode['action_name']='#';
            //$rootNode['type']=2;
        }

        foreach ($methods as $method) {

            //处理当前控制器下的每个action
            $admin['action_name'] = self::parsePath($prefix, $method);
            $methodName = $method->getName();
            if (substr($methodName, 0, 2) === '__') {
                continue;
            }

            if (isset($methodMetadata[$methodName]) && !empty($adminNodeData)) {

                $node = self::handleAdminNode($methodMetadata[$methodName]);
                $node['control_name'] = $prefix;
                $node['action_name'] = $methodName;
                //$node['type'] = 2;

                $adminNode[]= $node;

            }
        }
//        if(!empty($rootNode)){
//            array_push($adminNode,$rootNode);
//        }
        return ['adminNode'=>array_filter($adminNode),'rootNode'=>$rootNode];
    }

    public static function handleController(string $className, Controller $annotation, array $methodMetadata = [], AdminNode $adminNodeData = null)
    {
        if (! $methodMetadata) {
            return;
        }
        $prefix = self::getPrefix($className, $annotation->prefix);
        $rootNode = $adminNode = [];

        if(!empty($adminNodeData)){
            $rootNode = $adminNodeData->toArray();
            //类节点注解不为空
            $rootNode['parent_id']=0;
            $rootNode['control_name']=$prefix;
            $rootNode['action_name']='#';
            //$rootNode['type']=2;
        }

        $mappingAnnotations = [
            RequestMapping::class,
            GetMapping::class,
            PostMapping::class,
            PutMapping::class,
            PatchMapping::class,
            DeleteMapping::class,
        ];

        foreach ($methodMetadata as $methodName => $values) {
            $path = '';

            if(isset($values[AdminNode::class])){

                foreach ($mappingAnnotations as $mappingAnnotation) {
                    $mapping = $values[$mappingAnnotation] ?? null;

                    /** @var Mapping $mapping */
                    if (!empty($mapping)) {

                        if (! isset($mapping->path) || ! isset($mapping->methods) || ! isset($mapping->options)) {
                            continue;
                        }
                        $path = $mapping->path;
                        if ($path === '') {
                            $path = '#';
                        }
                    }
                }
                $node = self::handleAdminNode($values);
                $node['control_name'] = $prefix;
                $node['action_name'] = $path;
                //$node['type'] = 2;

                $adminNode[]= $node;
            }
        }
//        if(!empty($rootNode)){
//            array_push($adminNode,$rootNode);
//        }
        return ['adminNode'=>array_filter($adminNode),'rootNode'=>$rootNode];
    }

    protected static function handleAdminNode(array $metadata):array
    {

        $adminNodes = $metadata[AdminNode::class]?? null;
        if(!empty($adminNodes)){
            return $adminNodes->toArray();
        }else{
            return [];
        }
    }
    protected static function getPrefix(string $className, string $prefix): string
    {
        if (! $prefix) {
            $handledNamespace = Str::replaceFirst('Controller', '', Str::after($className, '\\Controller\\'));
            $handledNamespace = str_replace('\\', '/', $handledNamespace);
            $prefix = Str::snake($handledNamespace);
            $prefix = str_replace('/_', '/', $prefix);
        }
        if ($prefix[0] !== '/') {
            $prefix = '/' . $prefix;
        }
        return $prefix;
    }

    protected static function parsePath(string $prefix, ReflectionMethod $method): string
    {
        return $prefix . '/' . $method->getName();
    }

    public static function start()
    {
        $collector = AnnotationCollector::list();
        $adminNodes = [];//方法注解生成的路由节点
        $rootNodes= [];//类注解生成的根节点

        foreach ($collector as $className => $metadata) {
            if (isset($metadata['_c'][AutoController::class])) {
                if (isset($metadata['_c'][Controller::class])) {
                    $message = sprintf('NodController: AutoController annotation can\'t use with Controller annotation at the same time in %s.', $className);
                    throw new ConflictAnnotationException($message);
                }
                //处理AutoController内的相关节点信息
                $handlerAuto = self::handleAutoController($className, $metadata['_c'][AutoController::class], $metadata['_m'] ?? [], $metadata['_c'][AdminNode::class]??null);
                $adminNodes = array_merge($adminNodes,$handlerAuto['adminNode']);
                $rootNodes[] = $handlerAuto['rootNode'];
            }
            if (isset($metadata['_c'][Controller::class])) {
                //处理Controller内的相关节点信息
                $handler = self::handleController($className, $metadata['_c'][Controller::class], $metadata['_m'] ?? [], $metadata['_c'][AdminNode::class]??null);
                $adminNodes = array_merge($adminNodes,$handler['adminNode']);
                $rootNodes[] = $handler['rootNode'];
            }
        }
        return ['adminNodes'=>array_filter($adminNodes),'rootNodes'=>array_filter($rootNodes)];
    }
}